package com.sky.zero.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.sky.zero.common.generate.function.ClassField;
import com.sky.zero.exception.BIZException;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class TreeUtil {

    /**
     * 列表转树形结构
     * list  源数据
     * parentId  根节点id
     * clazz  返回类型
     * id    id名称
     * pid   上级id名称
     * children 子节点名称
     */
    public static <E, P> List<E> listToTree(List<E> list, P parentId, Class<E> clazz, ClassField<E> id, ClassField<E> pid, ClassField<E> children) {
        List<Map<String, Object>> mapList = new ArrayList<>();
        try {
            list.forEach(e -> mapList.add(BeanUtil.beanToMap(e)));
            String idName = FunctionUtil.getFieldName(id);
            String pidName = FunctionUtil.getFieldName(pid);
            String childrenName = FunctionUtil.getFieldName(children);
            // 获取根节点
            List<Map<String, Object>> rootList = mapList.stream().filter(a -> a.get(pidName) != null && a.get(pidName).equals(parentId))
                    .collect(Collectors.toList());
            // 删除根节点
            mapList.removeIf(c -> c.get(pidName) == null || c.get(pidName).equals(parentId));
            List<Map<String, Object>> lists = recursion(rootList, mapList, idName, pidName, childrenName);
            list.clear();
            for (Map<String, Object> mp : lists) {
                list.add(BeanUtil.mapToBean(mp, clazz, false, CopyOptions.create()));
            }
        } catch (Exception e) {
            throw new BIZException(e);
        }
        return list;
    }

    private static List<Map<String, Object>> recursion(List<Map<String, Object>> rootList, List<Map<String, Object>> list, String idName, String pidName, String childrenName) {
        for (Map<String, Object> a : rootList) {
            List<Map<String, Object>> maps = list.stream().filter(l -> l.get(pidName).equals(a.get(idName))).collect(Collectors.toList());
            a.put(childrenName, maps);
            List<Object> collect = maps.stream().map(m -> m.get(idName)).distinct().collect(Collectors.toList());
            list.removeIf(l -> collect.contains(l.get(idName)));
            recursion(maps, list, idName, pidName, childrenName);
        }
        return rootList;
    }
}
